package com.api.apigateway.ratelimit;

import com.alibaba.nacos.shaded.org.checkerframework.checker.units.qual.C;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.ratelimit.AbstractRateLimiter;
import org.springframework.cloud.gateway.support.ConfigurationService;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import reactor.core.publisher.Mono;

import java.time.Instant;
import java.util.*;


/**
 * 动态限流器 - 从 Redis 读取配置
 *
 * 核心思想：
 * 1. 限流配置不再写死在 YAML 中
 * 2. 从 Redis 动态读取 replenishRate 和 burstCapacity
 * 3. 支持实时更新，无需重启服务
 */
@Slf4j
public class DynamicRedisRateLimiter extends AbstractRateLimiter<DynamicRedisRateLimiter.Config> {

    public static final String  CONFIGURATION_PROPERTY_NAME = "dynamic-redis-rate-limiter";
    // Redis key 前缀
    private static final String RATE_LIMIT_CONFIG_KEY = "api:rate_limit:config:%s";  // 配置 key47

    private static final String RATE_LIMIT_STATE_KEY = "request_rate_limiter:%s:%s"; // 状态 key
    // 默认配置
    private static final int DEFAULT_REPLENISH_RATE = 50;
    private static final int DEFAULT_BURST_CAPACITY = 100;

    private final ReactiveRedisTemplate<String, Object> reactiveRedisTemplate;
    private final RedisScript<List<Long>> script;

    public DynamicRedisRateLimiter(
            ReactiveRedisTemplate<String, Object> reactiveRedisTemplate,
            RedisScript<List<Long>> script) {
        super(Config.class, CONFIGURATION_PROPERTY_NAME, null);
        this.reactiveRedisTemplate = reactiveRedisTemplate;
        this.script = script;
    }


    @Override
    public Mono<Response> isAllowed(String routeId, String id) {
        // 1. 获取动态配置（从 Redis 读取）
        return getDynamicConfig(routeId, id)
                .flatMap(config->{
                    // 2. 执行限流逻辑
                    return executeLimitCheck(routeId, id, config);
                }).onErrorResume(e->{
                    log.error("动态限流异常，使用默认配置", e);
                    // 降级：使用默认配置
                    Config defaultConfig = new Config()
                            .setReplenishRate(DEFAULT_REPLENISH_RATE)
                            .setBurstCapacity(DEFAULT_BURST_CAPACITY);
                    return executeLimitCheck(routeId, id, defaultConfig);
                });
    }
    /**
     * 执行限流检查（使用 Redis Lua 脚本）
     */
    private Mono<Response> executeLimitCheck(String routeId, String id, Config config) {
         int replenishRate = config.getReplenishRate();
         int burstCapacity = config.getBurstCapacity();
         int requestedTokens = config.getRequestedTokens();

        if (replenishRate <= 0 || burstCapacity <= 0 || requestedTokens <= 0) {
            log.error("限流参数无效: replenishRate={}, burstCapacity={}, requestedTokens={}",
                    replenishRate, burstCapacity, requestedTokens);
            return Mono.just(new Response(false, new HashMap<>()));
        }

        String baseKey = String.format(RATE_LIMIT_STATE_KEY, routeId, id);
        List<String> keys = Arrays.asList(
                baseKey + ".tokens",      // KEYS[1]
                baseKey + ".timestamp"    // KEYS[2]
        );;

        List<String> scriptArgs = Arrays.asList(
                String.valueOf(replenishRate),
                String.valueOf(burstCapacity),
                String.valueOf(Instant.now().getEpochSecond()),
                String.valueOf(requestedTokens)
        );
        return Mono.from(reactiveRedisTemplate.execute(script, keys, scriptArgs)
                .flatMap(results -> {
                    boolean allowed = results.get(0) == 1L;
                    long tokensLeft = results.get(1);
                    log.info("动态限流：allowed={}, tokensLeft={}",allowed,tokensLeft);
                    Response response = new Response(allowed,
                            getHeaders(config, tokensLeft));

                    if (!allowed) {
                        log.warn("触发动态限流: routeId={}, id={}, limit={} QPS",
                                routeId, id, replenishRate);
                    }
                    return Mono.just(response);

                }).onErrorResume(throwable -> {
                    log.error("限流执行异常", throwable);
                    return Mono.just(new Response(false, new HashMap<>()));
                }));
    }

    private Map<String, String> getHeaders(Config config, Long tokensLeft) {
        Map<String, String> headers = new HashMap<>();
        headers.put("X-RateLimit-Remaining", tokensLeft.toString());
        headers.put("X-RateLimit-Burst-Capacity", String.valueOf(config.getBurstCapacity()));
        headers.put("X-RateLimit-Replenish-Rate", String.valueOf(config.getReplenishRate()));
        return headers;
    }
    /**
     * 从 Redis 动态获取限流配置
     *
     * 配置存储格式：
     * key: api:rate_limit:config:{interfaceId}
     * value: { "replenishRate": 100, "burstCapacity": 200 }
     */
    private Mono<Config> getDynamicConfig(String routeId, String id) {
        // 从 id 中提取 interfaceId（根据实际业务调整）
        String interfaceId= extractInterfaceId(routeId);
        String configKey = String.format(RATE_LIMIT_CONFIG_KEY, interfaceId);
        return reactiveRedisTemplate.opsForHash().entries(configKey)
                .collectMap(Map.Entry::getKey,Map.Entry::getValue)
                .map(configMap->{
                    log.info("读取限流配置: interfaceId={}, configMap={}", interfaceId, configMap);

                    int replenishRate = getIntValue(configMap, "replenishRate", DEFAULT_REPLENISH_RATE);
                    int burstCapacity = getIntValue(configMap, "burstCapacity", DEFAULT_BURST_CAPACITY);
                    log.info("动态读取限流配置: interfaceId={}, replenishRate={}, burstCapacity={}",
                            interfaceId, replenishRate, burstCapacity);

                    return new Config()
                            .setBurstCapacity(burstCapacity)
                            .setReplenishRate(replenishRate)
                            .setRequestedTokens(1);
                })
                .defaultIfEmpty(new Config().setBurstCapacity(DEFAULT_BURST_CAPACITY)
                        .setReplenishRate(DEFAULT_REPLENISH_RATE)
                        .setRequestedTokens(1));
    }

    /**
     * 提取接口 ID（根据实际业务调整）
     * 例如：rate_limit:user123 -> user123
     */
    private String extractInterfaceId(String id) {
        // 简化实现：假设 id 就是 interfaceId
        // 实际可能需要从请求路径或其他地方提取
        return id.replace("api:gateway:api_route_", "");
    }

    private int getIntValue(Map<Object, Object> map, String key, int defaultValue) {
        Object value = map.get(key);
        if (value instanceof Number) {
            return ((Number) value).intValue();
        }
        if (value instanceof String) {
            try {
                return Integer.parseInt(value.toString());
            } catch (NumberFormatException e) {
                return defaultValue;
            }
        }
        return defaultValue;
    }
    @Validated
    public static class Config {
        private int replenishRate;
        private int burstCapacity;
        private int requestedTokens = 1;

        public int getReplenishRate() {
            return replenishRate;
        }

        public Config setReplenishRate(int replenishRate) {
            this.replenishRate = replenishRate;
            return this;
        }

        public int getBurstCapacity() {
            return burstCapacity;
        }

        public Config setBurstCapacity(int burstCapacity) {
            this.burstCapacity = burstCapacity;
            return this;
        }

        public int getRequestedTokens() {
            return requestedTokens;
        }

        public Config setRequestedTokens(int requestedTokens) {
            this.requestedTokens = requestedTokens;
            return this;
        }
    }
}
